/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.tutorial.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fhs.trans.service.impl.TransService;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.biz.modular.course.entity.EduCourse;
import vip.xiaonuo.biz.modular.course.service.EduCourseService;
import vip.xiaonuo.biz.modular.klass.entity.EduKlass;
import vip.xiaonuo.biz.modular.klass.service.EduKlassService;
import vip.xiaonuo.biz.modular.teacher.service.EduTeacherService;
import vip.xiaonuo.biz.modular.tutorial.enums.EduTutorialStateEnum;
import vip.xiaonuo.biz.modular.tutorial.param.*;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.tutorial.entity.EduTutorial;
import vip.xiaonuo.biz.modular.tutorial.mapper.EduTutorialMapper;
import vip.xiaonuo.biz.modular.tutorial.service.EduTutorialService;
import vip.xiaonuo.common.util.CommonResponseUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 配课Service接口实现类
 *
 * @author ahui
 * @date 2023/05/26 19:06
 **/
@Service
public class EduTutorialServiceImpl extends ServiceImpl<EduTutorialMapper, EduTutorial> implements EduTutorialService {

    @Resource
    private EduCourseService eduCourseService;

    @Resource
    private EduKlassService eduKlassService;

    @Resource
    private EduTeacherService eduTeacherService;

    @Resource
    private TransService transService;

    @Override
    public Page<EduTutorial> page(EduTutorialPageParam eduTutorialPageParam) {
        QueryWrapper<EduTutorial> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(eduTutorialPageParam.getKlassId())) {
            queryWrapper.lambda().eq(EduTutorial::getKlassId, eduTutorialPageParam.getKlassId());
        }
        if (ObjectUtil.isNotEmpty(eduTutorialPageParam.getCourseId())) {
            queryWrapper.lambda().eq(EduTutorial::getCourseId, eduTutorialPageParam.getCourseId());
        }
        if (ObjectUtil.isNotEmpty(eduTutorialPageParam.getState())) {
            queryWrapper.lambda().eq(EduTutorial::getState, eduTutorialPageParam.getState());
        }
        if (ObjectUtil.isAllNotEmpty(eduTutorialPageParam.getSortField(), eduTutorialPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(eduTutorialPageParam.getSortOrder());
            queryWrapper.orderBy(true, eduTutorialPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(eduTutorialPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(EduTutorial::getKlassId);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(EduTutorialAddParam eduTutorialAddParam) {
        EduTutorial eduTutorial = BeanUtil.toBean(eduTutorialAddParam, EduTutorial.class);
        eduTutorial.setState(EduTutorialStateEnum.DOING.getValue());
        this.save(eduTutorial);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(EduTutorialEditParam eduTutorialEditParam) {
        EduTutorial eduTutorial = this.queryEntity(eduTutorialEditParam.getId());
        EduCourse eduCourse = eduCourseService.getBaseMapper().selectById(eduTutorial.getCourseId());
        BeanUtil.copyProperties(eduTutorialEditParam, eduTutorial);
        if (ObjectUtil.isNotEmpty(eduTutorialEditParam.getToWeek()) && ObjectUtil.isNotEmpty(eduTutorial.getFromWeek())) {
            eduTutorial.setWeekHour(
                    eduCourse.getClassHour() / (eduTutorialEditParam.getToWeek() - eduTutorial.getFromWeek())
            );
        }
        if (!ObjectUtil.isNotEmpty(eduTutorial.getSize()) && ObjectUtil.isNotEmpty(eduTutorial.getKlassId())) {
            eduTutorial.setSize(eduKlassService.queryEntity(eduTutorial.getKlassId()).getSize());
        }
        this.updateById(eduTutorial);
    }

    @Override
    public void batchEdit(EduTutorialBatchEditParam eduTutorialBatchEditParam) {
        QueryWrapper<EduTutorial> eduTutorialQueryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(eduTutorialBatchEditParam.getTutorialIds())) {
            eduTutorialQueryWrapper.lambda().in(EduTutorial::getId
                    , StrUtil.split(eduTutorialBatchEditParam.getTutorialIds()
                            , StrUtil.COMMA));
        }
        List<EduTutorial> eduTutorials = this.list(eduTutorialQueryWrapper);
        eduTutorials.stream().map(eduTutorial -> {
            this.updateById(eduTutorial);
            return eduTutorial;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<EduTutorialIdParam> eduTutorialIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(eduTutorialIdParamList, EduTutorialIdParam::getId));
    }

    @Override
    public EduTutorial detail(EduTutorialIdParam eduTutorialIdParam) {
        return this.queryEntity(eduTutorialIdParam.getId());
    }

    @Override
    public EduTutorial queryEntity(String id) {
        EduTutorial eduTutorial = this.getById(id);
        if (ObjectUtil.isEmpty(eduTutorial)) {
            throw new CommonException("配课不存在，id值为：{}", id);
        }
        return eduTutorial;
    }

    @Override
    public void exportTutorial(EduTutorialExportParam eduTutorialExportParam, HttpServletResponse response) {
        try {
            QueryWrapper<EduTutorial> queryWrapper = new QueryWrapper<>();
            if (ObjectUtil.isNotEmpty(eduTutorialExportParam.getTutorialIds())) {
                queryWrapper.lambda().in(EduTutorial::getId, StrUtil.split(eduTutorialExportParam.getTutorialIds(), StrUtil.COMMA));
            } else if (ObjectUtil.isNotEmpty(eduTutorialExportParam.getKlassId())) {
                List<EduKlass> eduKlasses = eduKlassService.selectByName(eduTutorialExportParam.getKlassId());
                List<String> klassIds = eduKlasses.stream().map(EduKlass::getId).collect(Collectors.toList());
                queryWrapper.lambda().in(EduTutorial::getKlassId, klassIds);
            }
            List<EduTutorial> eduTutorialList = this.list(queryWrapper);
            if (ObjectUtil.isEmpty(eduTutorialList)) {
                throw new CommonException("无数据可导出");
            }
            transService.transBatch(eduTutorialList);
            eduTutorialList = CollectionUtil.sort(eduTutorialList, Comparator.comparing(EduTutorial::getCourseId));
            EduKlass eduKlass = eduKlassService.getBaseMapper()
                    .selectOne(new QueryWrapper<EduKlass>()
                            .lambda()
                            .like(EduKlass::getId, eduTutorialExportParam.getKlassId()));
            EduTutorialExportHeader header = new EduTutorialExportHeader();
            // TODO remove hardcoded year and semester
            header.setYear("2024-2025");
            header.setSemester("2");
            header.setKlassName(eduKlass.getName());
            header.setMajor(eduKlass.getMajor());
            header.setKlassOwner(eduKlass.getOwner());
            header.setKlassSize(eduKlass.getSize());
            header.setKlassGrade(eduKlass.getYear()-2000);

            // 设置响应头
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode(eduKlass.getName() + "课程表", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            response.setContentType("application/octet-stream;charset=UTF-8");


            ClassPathResource resource = new ClassPathResource("tutorialExportTemplate.xlsx");
            OutputStream out = response.getOutputStream();
            InputStream inputStream = resource.getInputStream();
            ExcelWriter writer = EasyExcel.write(out).withTemplate(inputStream).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            writer.fill(eduTutorialList, fillConfig, writeSheet);
            writer.fill(header, writeSheet);
            writer.finish();
            out.flush();
            inputStream.close();
        } catch (Exception e) {
            log.error(">>> 导出异常：", e);
            try {
                CommonResponseUtil.renderError(response, "导出失败,请先查询班级");
            } catch (IOException ex) {
                log.error(">>> 导出异常：", ex);
            }
        }

    }

    @Override
    public void combineClass(EduTutorialExportParam eduTutorialExportParam) {
        QueryWrapper<EduTutorial> eduTutorialQueryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(eduTutorialExportParam.getTutorialIds())) {
            eduTutorialQueryWrapper.lambda().in(EduTutorial::getId, StrUtil.split(eduTutorialExportParam.getTutorialIds(), StrUtil.COMMA));
        }
        List<EduTutorial> eduTutorials = this.list(eduTutorialQueryWrapper);
        List<String> klassIds = eduTutorials.stream().map(EduTutorial::getKlassId).collect(Collectors.toList());
        List<String> ids = eduTutorials.stream().map(EduTutorial::getId).collect(Collectors.toList());
        List<String> klassNames = eduKlassService.getBaseMapper()
                .selectBatchIds(klassIds)
                .stream()
                .map(EduKlass::getName)
                .collect(Collectors.toList());
        StringBuilder stringBuilder = new StringBuilder();
        for (String name : klassNames) {
            stringBuilder.append(name).append(",");
        }
        String s = stringBuilder.toString();
        if (s.endsWith(",")) {
            s = s.substring(0, s.length() - 1) + "合班"; // 移除最后一个逗号
        }
        UpdateWrapper<EduTutorial> eduTutorialUpdateWrapper = new UpdateWrapper<>();
        eduTutorialUpdateWrapper.lambda()
                .in(EduTutorial::getId, ids)
                .set(EduTutorial::getRemarks, s)
                .set(EduTutorial::getCombineClass, true);
        this.update(eduTutorialUpdateWrapper);
    }

    @Override
    public void splitClass(EduTutorialExportParam eduTutorialExportParam) {
        QueryWrapper<EduTutorial> eduTutorialQueryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(eduTutorialExportParam.getTutorialIds())) {
            eduTutorialQueryWrapper.lambda().in(EduTutorial::getId
                    , StrUtil.split(eduTutorialExportParam.getTutorialIds()
                            , StrUtil.COMMA));
        }
        List<EduTutorial> eduTutorials = this.list(eduTutorialQueryWrapper);
        eduTutorials.stream().map(eduTutorial -> {
            eduTutorial.setSize(eduTutorial.getSize() / 2);
            this.updateById(eduTutorial);
            return eduTutorial;
        }).collect(Collectors.toList());
        eduTutorials.stream().map(eduTutorial -> {
            eduTutorial.setSize(eduTutorial.getSize());
            eduTutorial.setId(null);
            this.save(eduTutorial);
            return eduTutorial;
        }).collect(Collectors.toList());
    }
}
